package org.cashbook.IO.dataManager;

import java.util.HashMap;
import java.util.Map;

import org.cashbook.core.objects.account.IAccount;
import org.cashbook.core.objects.category.ICategory;
import org.cashbook.core.objects.keyword.IKeyword;
import org.cashbook.core.objects.transaction.TransactionList;
import org.cashbook.entities.IUser;
import org.cashbook.utilities.UtilitiesFactory;
import org.cashbook.utilities.logger.ILogger;

public abstract class AbstractDataManager implements IDataManager {
	protected boolean categoryUptodate = true;
	protected boolean subCategoryUptodate = true;
	protected boolean keywordUptodate = true;
	protected boolean accountUptodate = true;
	protected boolean transactionUptodate = true;
	protected boolean userUptodate = true;
	protected ILogger logger;
	protected Map<String, TransactionList> transactionBuffer = new HashMap<String, TransactionList>();
	protected Map<String, ICategory> categoryBuffer = new HashMap<String, ICategory>();
	protected Map<String, ICategory> subCategoryBuffer = new HashMap<String, ICategory>();
	protected Map<String, IKeyword> keywordBuffer = new HashMap<String, IKeyword>();
	protected Map<String, IAccount> accountBuffer = new HashMap<String, IAccount>();
	protected Map<String, IUser> userBuffer = new HashMap<String, IUser>();
	
	public AbstractDataManager() {
		logger = UtilitiesFactory.getLogger();
		logger.info("DataManager created [Type " + getDataManagerType() + "]", this);
		logger.info("Starting data retrieval from database", this);
		loadDataFromDB();
		logger.info("Data retrieval ended", this);
	}
	
	protected abstract void loadDataFromDB();

	@Override
	public boolean checkAllBuffered() {
		return categoryUptodate && keywordUptodate && accountUptodate && transactionUptodate && userUptodate && subCategoryUptodate;
	}

	@Override
	public TransactionList readTransactionsFromBuffer(String month,
			Integer year) {
		TransactionList resultTransaction;
		
		resultTransaction = transactionBuffer.get("" + year + UtilitiesFactory.convertMonthToInt(month));
		if(resultTransaction == null) {
			resultTransaction = new TransactionList();
			transactionBuffer.put("" + year + UtilitiesFactory.convertMonthToInt(month), resultTransaction);
			logger.info("New empty transactionlist created for month " + month + ", year " + year + "; was null", this);
		}
		if(resultTransaction.isEmpty())
			logger.warning("Transaction buffer for month " + month + ", year " + year + " is empty", this);
		else
			logger.info("Returning " + resultTransaction.size() + " transaction for month " + month + ", year " + year, this);
		transactionUptodate = false;
		return resultTransaction;
	}

	@Override
	public Map<String, ICategory> readCategoriesFromBuffer() {
		if(categoryBuffer.isEmpty())
			logger.warning("Category buffer is empty", this);
		else
			logger.finest("Returning category buffer with " + categoryBuffer.size() + " categories", this);
		categoryUptodate = false;
		return categoryBuffer;
	}

	@Override
	public Map<String, IKeyword> readKeywordsFromBuffer() {
		if(keywordBuffer.isEmpty())
			logger.warning("Keyword buffer is empty", this);
		else
			logger.finest("Returning keyword buffer with " + keywordBuffer.size() + " keywords", this);
		keywordUptodate = false;
		return keywordBuffer;
	}

	@Override
	public Map<String, IAccount> readAccountsFromBuffer() {
		if(accountBuffer.isEmpty())
			logger.warning("Account buffer is empty", this);
		else
			logger.finest("Returning account buffer with " + accountBuffer.size() + " accounts", this);
		accountUptodate = false;
		return accountBuffer;
	}

	@Override
	public Map<String, IUser> readUsersFromBuffer() {
		if(userBuffer.isEmpty())
			logger.warning("User buffer is empty", this);
		else
			logger.finest("Returning user buffer with " + userBuffer.size() + " users", this);
		userUptodate = false;
		return userBuffer;
	}

	@Override
	public void writeTransactionsToBuffer(TransactionList transactions, String month, int year) {
		logger.warning("Transaction buffer updated for month " + month + ", year " + year + "; New size is " + transactions.size(), this);
		transactionBuffer.put("" + year + UtilitiesFactory.convertMonthToInt(month), transactions);
		transactionUptodate = true;
	}

	@Override
	public void writeCategoryToBuffer(Map<String, ICategory> categories) {
		int oldSize = categoryBuffer.size();
		
		if(categories.size() == 0)
			logger.warning("New category buffer size is 0", this);
		else
			logger.info("Category buffer updated; Old size was " + oldSize + ", new size is " + categories.size(), this);
		categoryBuffer = categories;
		categoryUptodate = true;
	}

	@Override
	public void writeKeywordToBuffer(Map<String, IKeyword> keywords) {
		int oldSize = keywordBuffer.size();
		
		if(keywords.size() == 0)
			logger.warning("New keyword buffer size is 0", this);
		else
			logger.info("Keyword buffer updated; Old size was " + oldSize + ", new size is " + keywords.size(), this);
		keywordBuffer = keywords;
		keywordUptodate = true;
	}

	@Override
	public void writeAccountToBuffer(Map<String, IAccount> accounts) {
		int oldSize = accountBuffer.size();
		
		if(accounts.size() == 0)
			logger.warning("New account buffer size is 0", this);
		else
			logger.info("Account buffer updated; Old size was " + oldSize + ", new size is " + accounts.size(), this);
		accountBuffer = accounts;
		accountUptodate = true;
	}

	@Override
	public void writeUsersToBuffer(Map<String, IUser> users) {
		int oldSize = userBuffer.size();
		
		if(users.size() == 0)
			logger.warning("New user buffer size is 0", this);
		else
			logger.info("User buffer updated; Old size was " + oldSize + ", new size is " + users.size(), this);
		userBuffer = users;
		userUptodate = true;
	}

	@Override
	public void writeSubCategoryToBuffer(Map<String, ICategory> subCategories) {
		int oldSize = subCategoryBuffer.size();
		
		if(subCategories.size() == 0)
			logger.warning("New subcategory buffer size is 0", this);
		else
			logger.info("Subcategory buffer updated; Old size was " + oldSize + ", new size is " + subCategories.size(), this);
		subCategoryBuffer = subCategories;
		subCategoryUptodate = true;
	}

	@Override
	public Map<String, ICategory> readSubCategoriesFromBuffer() {
		if(subCategoryBuffer.isEmpty())
			logger.warning("Subcategory buffer is empty", this);
		else
			logger.finest("Returning subcategory buffer with " + subCategoryBuffer.size() + " subcategories", this);
		subCategoryUptodate = false;
		return subCategoryBuffer;
	}

}
